package com.atguigu.aclservice.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.atguigu.aclservice.entity.Permission;
import com.atguigu.aclservice.entity.RolePermission;
import com.atguigu.aclservice.entity.User;
import com.atguigu.aclservice.helper.MenuHelper;
import com.atguigu.aclservice.mapper.PermissionMapper;
import com.atguigu.aclservice.service.PermissionService;
import com.atguigu.aclservice.service.RolePermissionService;
import com.atguigu.aclservice.service.UserService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.List;

import static com.atguigu.aclservice.helper.PermissionHelper.build;

/**
 * <p>
 * 菜单栏（权限）操作类
 * </p>
 *
 * @author He Wentao
 * @since 2022/10/9 22:28
 */
@Service
public class PermissionServiceImpl extends ServiceImpl<PermissionMapper, Permission> implements PermissionService {

    @Autowired
    private RolePermissionService rolePermissionService;

    @Autowired
    private UserService userService;

    /**
     * 获取全部菜单
     * @return 返回菜单栏树状结构
     */
    @Override
    public List<Permission> queryAllMenu() {
        QueryWrapper<Permission> wrapper = new QueryWrapper<>();
        wrapper.orderByDesc("id");

        // 查询所有菜单栏，使用排序，增加查找效率
        List<Permission> permissionList = baseMapper.selectList(wrapper);

        // 进行菜单栏构建，并进行返回
        return build(permissionList);
    }

    /**
     * 根据角色获取菜单栏
     * @param roleId 角色 id
     * @return 构建好的菜单栏
     */
    @Override
    public List<Permission> selectAllMenu(String roleId) {

        // 查询 权限表 ，并根据 id 进行排序
        List<Permission> allPermissionList = baseMapper.selectList(new QueryWrapper<Permission>().orderByAsc("CAST(id AS SIGNED)"));

        // 根据角色 id 获取到所有的角色权限 id
        List<RolePermission> rolePermissionList = rolePermissionService.list(new QueryWrapper<RolePermission>().eq("role_id",roleId));

        // 遍历查询到的所有菜单栏（权限）
        for (Permission permission : allPermissionList) {
            // 遍历查询到的所有 角色权限 id
            for (RolePermission rolePermission : rolePermissionList) {
                // 判断角色权限 id，和当前权限 id 是否一致
                if (rolePermission.getPermissionId().equals(permission.getId())) {
                    // 如果一致，则表示角色拥有此权限，我们进行一个标记
                    // 将他设置为 “选中状态” 然后前端根据这个值，进行显示状态栏即可。。。后面有时间完善。。。
                    permission.setSelect(true);
                }
            }
        }

        // 循环执行完成之后，进行构建菜单栏，并进行返回
        return build(allPermissionList);
    }


    /**
     * 给角色分配权限
     * @param roleId  角色 id
     * @param permissionIds  权限 id
     */
    @Override
    public void saveRolePermissionRealtionShip(String roleId, String[] permissionIds) {

        // 先删除角色的相关权限
        rolePermissionService.remove(new QueryWrapper<RolePermission>().eq("role_id", roleId));

        // 创建 角色权限集合
        List<RolePermission> rolePermissionList = new ArrayList<>();

        // 遍历权限 id 集合
        for(String permissionId : permissionIds) {
            // 判断是否为空
            if(StringUtils.isEmpty(permissionId)) continue;

            // 创建角色权限对象
            RolePermission rolePermission = new RolePermission();
            // 设置角色 id
            rolePermission.setRoleId(roleId);
            // 设置权限 id
            rolePermission.setPermissionId(permissionId);
            // 保存到 角色权限 集合
            rolePermissionList.add(rolePermission);
        }
        // 批量保存
        rolePermissionService.saveBatch(rolePermissionList);
    }

    /**
     * 递归删除菜单
     * @param id 菜单栏 id
     */
    @Override
    public void removeChildById(String id) {
        // 创建一个集合，用于存放要删除的菜单栏 id
        List<String> idList = new ArrayList<>();

        // 进行查询 id 下的子菜单栏 id
        this.selectChildListById(id, idList);

        // 查询完毕后，将最开始的 id 也放到里面，进行删除
        idList.add(id);

        // 进行删除
        baseMapper.deleteBatchIds(idList);
    }


    /**
     * 根据菜单栏id，获取子菜单栏 id
     * @param id 父级菜单栏 id
     * @param idList 子菜单栏 id 集合
     */
    private void selectChildListById(String id, List<String> idList) {

        // 查询 子菜单栏 id
        List<Permission> childList = baseMapper.selectList(
                new QueryWrapper<Permission>().eq("pid", id).select("id"));

        // 遍历获取到的 Permission 对象
        childList.stream().forEach(item -> {
            // 将 Permission 对象中的 id 存放到集合中
            idList.add(item.getId());
            // 查询这个 id 是否还有子菜单栏，有也放到 集合 中去
            this.selectChildListById(item.getId(), idList);
            // 地址引用，不需要返回
        });
    }


    /**
     * 根据 用户id 获取 用户拥有的 菜单栏 “权限值集合”
     * @param id 用户 id
     * @return 用户拥有的 “权限值” 集合
     */
    @Override
    public List<String> selectPermissionValueByUserId(String id) {

        // 创建集合，保存拥有的权限
        List<String> selectPermissionValueList = null;

        // 判断是否是管理员
        if(this.isSysAdmin(id)) {
            //如果是系统管理员，获取所有权限
            selectPermissionValueList = baseMapper.selectAllPermissionValue();
        } else {
            // 不是则按照用户 id 获取对应的权限
            selectPermissionValueList = baseMapper.selectPermissionValueByUserId(id);
        }
        // 返回菜单栏 “权限值” 集合
        return selectPermissionValueList;
    }

    /**
     * 根据用户 id 拼接菜单栏，并进行返回
     * @param userId
     * @return
     */
    @Override
    public List<JSONObject> selectPermissionByUserId(String userId) {
        List<Permission> selectPermissionList = null;

        // 判断是否是 admin 管理员
        if(this.isSysAdmin(userId)) {
            //如果是超级管理员，直接获取所有菜单
            selectPermissionList = baseMapper.selectList(null);
        } else {
            // 如果不是，则根据 id 进行获取
            selectPermissionList = baseMapper.selectPermissionByUserId(userId);
        }

        // 使用工具类，进行构建菜单栏对象
        List<Permission> permissionList = build(selectPermissionList);

        // 使用工具类，构建 JSON 对象，并进行返回
        return MenuHelper.build(permissionList);
    }

    /**
     * 根据用户id，判断用户是否系统管理员
     * @param userId 用户id
     * @return  是否是管理员
     */
    private boolean isSysAdmin(String userId) {
        User user = userService.getById(userId);

        return null != user && "admin".equals(user.getUsername());
    }



    //==============================递归查询所有菜单================================================
    //获取全部菜单
    @Override
    public List<Permission> queryAllMenuGuli() {
        //1 查询菜单表所有数据
        QueryWrapper<Permission> wrapper = new QueryWrapper<>();
        wrapper.orderByDesc("id");
        List<Permission> permissionList = baseMapper.selectList(wrapper);
        //2 把查询所有菜单list集合按照要求进行封装
        List<Permission> resultList = bulidPermission(permissionList);
        return resultList;
    }

    //把返回所有菜单list集合进行封装的方法
    public static List<Permission> bulidPermission(List<Permission> permissionList) {

        //创建list集合，用于数据最终封装
        List<Permission> finalNode = new ArrayList<>();
        //把所有菜单list集合遍历，得到顶层菜单 pid=0菜单，设置level是1
        for(Permission permissionNode : permissionList) {
            //得到顶层菜单 pid=0菜单
            if("0".equals(permissionNode.getPid())) {
                //设置顶层菜单的level是1
                permissionNode.setLevel(1);
                //根据顶层菜单，向里面进行查询子菜单，封装到finalNode里面
                finalNode.add(selectChildren(permissionNode,permissionList));
            }
        }
        return finalNode;
    }

    private static Permission selectChildren(Permission permissionNode, List<Permission> permissionList) {
        //1 因为向一层菜单里面放二层菜单，二层里面还要放三层，把对象初始化
        permissionNode.setChildren(new ArrayList<Permission>());

        //2 遍历所有菜单list集合，进行判断比较，比较id和pid值是否相同
        for(Permission it : permissionList) {
            //判断 id和pid值是否相同
            if(permissionNode.getId().equals(it.getPid())) {
                //把父菜单的level值+1
                int level = permissionNode.getLevel()+1;
                it.setLevel(level);
                //如果children为空，进行初始化操作
                if(permissionNode.getChildren() == null) {
                    permissionNode.setChildren(new ArrayList<Permission>());
                }
                //把查询出来的子菜单放到父菜单里面
                permissionNode.getChildren().add(selectChildren(it,permissionList));
            }
        }
        return permissionNode;
    }

    //============递归删除菜单==================================
    @Override
    public void removeChildByIdGuli(String id) {
        //1 创建list集合，用于封装所有删除菜单id值
        List<String> idList = new ArrayList<>();
        //2 向idList集合设置删除菜单id
        this.selectPermissionChildById(id,idList);
        //把当前id封装到list里面
        idList.add(id);
        baseMapper.deleteBatchIds(idList);
    }

    //2 根据当前菜单id，查询菜单里面子菜单id，封装到list集合
    private void selectPermissionChildById(String id, List<String> idList) {
        //查询菜单里面子菜单id
        QueryWrapper<Permission>  wrapper = new QueryWrapper<>();
        wrapper.eq("pid",id);
        wrapper.select("id");
        List<Permission> childIdList = baseMapper.selectList(wrapper);
        //把childIdList里面菜单id值获取出来，封装idList里面，做递归查询
        childIdList.stream().forEach(item -> {
            //封装idList里面
            idList.add(item.getId());
            //递归查询
            this.selectPermissionChildById(item.getId(),idList);
        });
    }

    //=========================给角色分配菜单=======================
    @Override
    public void saveRolePermissionRealtionShipGuli(String roleId, String[] permissionIds) {
        //roleId角色id
        //permissionId菜单id 数组形式
        //1 创建list集合，用于封装添加数据
        List<RolePermission> rolePermissionList = new ArrayList<>();
        //遍历所有菜单数组
        for(String perId : permissionIds) {
            //RolePermission对象
            RolePermission rolePermission = new RolePermission();
            rolePermission.setRoleId(roleId);
            rolePermission.setPermissionId(perId);
            //封装到list集合
            rolePermissionList.add(rolePermission);
        }
        //添加到角色菜单关系表
        rolePermissionService.saveBatch(rolePermissionList);
    }
}
